/*
 *------------------------------------------------------------------------------
 * @File      :    ar0230_dvp.c
 * @Date      :    2021-3-20
 * @Author    :    lomboswer <lomboswer@lombotech.com>
 * @Brief     :    Source file for MDP(Media Development Platform).
 *
 * Copyright (C) 2020-2021, LomboTech Co.Ltd. All rights reserved.
 *------------------------------------------------------------------------------
 */
#include "ei_comm_camera.h"
#include "camera_usr.h"

#ifdef __cplusplus
#if __cplusplus
extern "C" {
#endif
#endif /* __cplusplus */

#define SNS_ID 0230
#define SNS_NAME  "ar0230_dvp"
#define DEV_TYPE DVP

static SNS_STATE_S g_sastSns[VISS_MAX_DEV_NUM];

static const SNS_REG_S s_aInitRegList[] = {
    {0x3ED6, 0x2CB3},
    {0x2436, 0x000E},
    {0x320C, 0x0180},
    {0x320E, 0x0300},
    {0x3210, 0x0500},
    {0x3204, 0x0B6D},
    {0x30FE, 0x0080},
    {0x3ED8, 0x7B99},
    {0x3EDC, 0x9BA8},
    {0x3EDA, 0x9B9B},
    {0x3092, 0x006F},
    {0x3EEC, 0x1C04},
    {0x30BA, 0x779C},
    {0x3EF6, 0xA70F},
    {0x3044, 0x0410},
    {0x3ED0, 0xFF44},
    {0x3ED4, 0x031F},
    {0x30FE, 0x0080},
    {0x3EE2, 0x8866},
    {0x3EE4, 0x6623},
    {0x3EE6, 0x2263},
    {0x30E0, 0x4283},
    {0x30F0, 0x1283},
    {0x3064, 0x1802},
    {0x301A, 0x10D8},   /* RESET_REGISTER */
    {0x30B0, 0x0118},   /* DIGITAL_TEST enable low power */
    {0x31AC, 0x100C},
    {0x302A, 0x0008},   /* VT_PIX_CLK_DIV */
    {0x302C, 0x0001},   /* VT_SYS_CLK_DIV */
    {0x302E, 0x0002},   /* PRE_PLL_CLK_DIV */
    {0x3030, 0x002C},   /* PLL_MULTIPLIER */
    {0x3036, 0x000C},   /* OP_PIX_CLK_DIV */
    {0x3038, 0x0001},   /* OP_SYS_CLK_DIV */
    {0x3002, 0x0000},   /* Y_ADDR_START */
    {0x3004, 0x0004},   /* X_ADDR_START */
    {0x3006, 0x0437},   /* Y_ADDR_END */
    {0x3008, 0x0783},   /* X_ADDR_END */
    {0x300A, 0x0465},   /* 1125 vts */
    {0x300C, 0x044C},   /* 1100 hts */
    {0x3012, 0x03F4},   /* 1046 */
    {0x30A2, 0x0001},
    {0x30A6, 0x0001},
    {0x30AE, 0x0001},
    {0x30A8, 0x0001},
    {0x3040, 0x0000},
    {0x31AE, 0x0301},
    {0x3082, 0x0009},
    {0x3176, 0x0080},
    {0x3178, 0x0080},
    {0x317A, 0x0080},
    {0x317C, 0x0080},
    {0x31E0, 0x0200},
    {0x2420, 0x0000},
    {0x2440, 0x0004},
    {0x2442, 0x0080},
    {0x301E, 0x0000},
    {0x2450, 0x0000},
    {0x320A, 0x0080},
    {0x31D0, 0x0001},
    {0x2400, 0x0001},
    {0x2410, 0x0005},
    {0x2412, 0x002D},
    {0x2444, 0xF400},
    {0x2446, 0x0001},
    {0x2438, 0x0010},
    {0x243A, 0x0012},
    {0x243C, 0xFFFF},
    {0x243E, 0x0100},
    {0x3206, 0x0B08},
    {0x3208, 0x1E13},
    {0x3202, 0x0080},
    {0x3200, 0x0002},
    {0x3190, 0x0000},
    {0x318A, 0x0E74},
    {0x318C, 0x0000},
    {0x318E, 0x0200},
    {0x3192, 0x0400},
    {0x3198, 0x183C},
    {0x3060, 0x000B},
    {0x3096, 0x0480},
    {0x3098, 0x0480},
    {0x3206, 0x0B08},
    {0x3208, 0x1E13},
    {0x3202, 0x0080},
    {0x3200, 0x0002},
    {0x3100, 0x0000},
    {0x306E, 0x9210},
    {0x30BA, 0x779C},
    {0x318E, 0x0200},
    //{0x301A, 0x10DC},
};

static CAMERA_POWER_ACT_S s_stPowerUpAct[] = {
    {SNS_RESET, SNS_DOWN},
    {SNS_DELAY, 10},
    {SNS_PWDN,  SNS_UP},
    {SNS_DELAY, 10},
    {SNS_PWDN,  SNS_DOWN},
    {SNS_DELAY, 20},
    {SNS_RESET, SNS_UP},
    {SNS_DELAY, 5},
};

static CAMERA_POWER_ACT_S s_sPowerDownAct[] = {
    {SNS_RESET, SNS_DOWN},
    {SNS_DELAY, 10},
    {SNS_PWDN,  SNS_UP},
};

static SNS_TYPE_ATTR_S s_astSnsAttr[] = {
    {
        .enSnsType                  = AR0230_DVP_1920_1080_30FPS_RAW12,
        .enPixelFormat              = PIX_FMT_RGB_BAYER_12BITS,
        .enRgbSeq                   = VISS_RGB_SEQ_GRBG,
        .stSize                     = {1920, 1080},
        .u32Mclock                  = 27000000,

        .u32Left                    = 0,
        .u32Top                     = 0,
        .u32Vts                     = 1125,
        .u32Hts                     = 1100,
        .u32Pclk                    = 37125000,

        .u32FrameRate                = 30,
        .astRegCfgs[0].pstRegs      = s_aInitRegList,
        .astRegCfgs[0].u32RegsCnt   = ARRAY_SIZE(s_aInitRegList),
    },
};

static int CAMERA_SetI2cInfo(VISS_DEV dev)
{
    SNS_STATE_S *pstSnsState = EI_NULL;

    SNS_GET_CTX(dev, pstSnsState);
    CAMERA_CHECK_POINTER(pstSnsState);

    if (pstSnsState->stI2cInfo.fd > 0) {
        return EI_SUCCESS;
    }

    pstSnsState->stI2cInfo.u8RegBits = 16;
    pstSnsState->stI2cInfo.u8ValBits = 16;
    pstSnsState->stI2cInfo.u16I2cBusNum = 1;
    pstSnsState->stI2cInfo.u16I2cDevAddr = 0x10;
    pstSnsState->pcName = SNS_NAME;

    return EI_SUCCESS;
}

static EI_S32 CAMERA_Detect(VISS_DEV VissDev)
{

    EI_U8 u8Tmp;
    EI_S32 s32Ret = EI_SUCCESS;
    SNS_STATE_S *pstSnsState = EI_NULL;
    I2C_INFO_S *pstI2cInfo = EI_NULL;

    SNS_GET_CTX(VissDev, pstSnsState);

    pstI2cInfo = &pstSnsState->stI2cInfo;

    CAMERA_CHECK_POINTER(pstI2cInfo->pfnReadReg);
    s32Ret = pstI2cInfo->pfnReadReg(pstSnsState, 0x3000, &u8Tmp);
    if (s32Ret != 0) {
        PRT_VISS_ERR("tmp=%x\n", u8Tmp);
        return EI_FAILURE;
    }

    PRT_VISS_INFO("id: 0x%04x.\n", u8Tmp);

    if (u8Tmp != 0x0056) {
        PRT_VISS_ERR("ID wrong! (0x%04x != 0x0056)\n", u8Tmp);
        return EI_FAILURE;
    }

    return EI_SUCCESS;
}

/* The following functions can be modified as needed */

static int CAMERA_I2cInit(VISS_DEV dev)
{
    SNS_STATE_S *pstSnsState = EI_NULL;
    int ret = EI_SUCCESS;

    SNS_GET_CTX(dev, pstSnsState);
    CAMERA_CHECK_POINTER(pstSnsState);

    ret = CAMERA_SetI2cInfo(dev);
    CAMERA_CHECK_SUCCESS(ret);

    ret = CAMERA_I2C_Reg_Ops(&pstSnsState->stI2cInfo);
    CAMERA_CHECK_SUCCESS(ret);

    return EI_SUCCESS;
}

static int CAMERA_I2cExit(VISS_DEV dev)
{
    SNS_STATE_S *pstSnsState = EI_NULL;

    SNS_GET_CTX(dev, pstSnsState);
    CAMERA_CHECK_POINTER(pstSnsState);

    return EI_SUCCESS;
}

static EI_S32 CAMERA_PowerUp(VISS_DEV VissDev)
{
    SNS_STATE_S *pstSnsState = EI_NULL;

    SNS_GET_CTX(VissDev, pstSnsState);

    CAMERA_SensorPowerUp(VissDev, pstSnsState);

    return 0;
}

static EI_S32 CAMERA_PowerDown(VISS_DEV VissDev)
{
    SNS_STATE_S *pstSnsState = EI_NULL;

    SNS_GET_CTX(VissDev, pstSnsState);

    CAMERA_SensorPowerDown(VissDev, pstSnsState);

    return 0;
}

static EI_S32 CAMERA_Init(VISS_DEV dev)
{
    EI_U32 j;
    const SNS_TYPE_ATTR_S *pstSnsType;
    SNS_STATE_S *pstSnsState = EI_NULL;
    EI_S32 s32Ret;

    SNS_GET_CTX(dev, pstSnsState);
    CAMERA_CHECK_POINTER(pstSnsState);

    pstSnsType = pstSnsState->pstSnsAttr;
    for (j = 0; j < MAX_COF; j++) {
        s32Ret = pstSnsState->stI2cInfo.pfnwriteRegList(pstSnsState,
                pstSnsType->astRegCfgs[j].pstRegs, pstSnsType->astRegCfgs[j].u32RegsCnt);
        if (s32Ret != EI_SUCCESS) {
            PRT_VISS_ERR("%s writeRegList err", SNS_NAME);
            return s32Ret;
        }
    }

    PRT_VISS_INFO("%s writeRegList success", SNS_NAME);

    return s32Ret;
}

static void CAMERA_Exit(VISS_DEV dev)
{
    CAMERA_I2cExit(dev);

    return;
}
static EI_S32 CAMERA_Stream(VISS_DEV dev, EI_BOOL bOn)
{
    SNS_STATE_S *pstSnsState = EI_NULL;
    EI_S32 s32Ret = EI_SUCCESS;
    EI_U16 tmp = 0;
    SNS_GET_CTX(dev, pstSnsState);
    CAMERA_CHECK_POINTER(pstSnsState);

    if (bOn) {
        s32Ret = pstSnsState->stI2cInfo.pfnWriteReg(pstSnsState, 0x301A, 0x10DC);
        if (s32Ret != EI_SUCCESS) {
            PRT_VISS_ERR("CAMERA_Stream*******%d\n", bOn);
        }
    } else {
        s32Ret = pstSnsState->stI2cInfo.pfnReadReg(pstSnsState, 0x301A, &tmp);
        tmp = tmp & (EI_U16)(~(1 << 2));
        s32Ret = pstSnsState->stI2cInfo.pfnWriteReg(pstSnsState, 0x301A, tmp);
        if (s32Ret != EI_SUCCESS) {
            PRT_VISS_ERR("CAMERA_Stream*******%d\n", bOn);
        }
    }

    PRT_VISS_INFO("CAMERA_Stream*******%d\n", bOn);
    return EI_SUCCESS;
}

static EI_S32 CAMERA_SetImageMode(VISS_DEV dev, SNS_TYPE_E enSnsType)
{
    SNS_STATE_S *pstSnsState = EI_NULL;

    SNS_GET_CTX(dev, pstSnsState);
    CAMERA_CHECK_POINTER(pstSnsState);

    pstSnsState->enSnsType = enSnsType;
    pstSnsState->bSyncInit = EI_FALSE;

    return EI_SUCCESS;
}

static EI_S32 CAMERA_EnumSnstype(VISS_DEV VissDev, EI_U32 u32Index, SNS_TYPE_E *peSnstype)
{
    const SNS_TYPE_ATTR_S *pstSnsType;

    if (u32Index >= ARRAY_SIZE(s_astSnsAttr))
        return EN_ERR_NO_FOUND;

    pstSnsType = &s_astSnsAttr[u32Index];

    *peSnstype = pstSnsType->enSnsType;

    return EI_SUCCESS;
}

static EI_S32 CAMERA_InitSensorExpFunction(SENSOR_EXP_FUNC_S *pstSensorExpFunc)
{
    CAMERA_CHECK_POINTER(pstSensorExpFunc);

    memset(pstSensorExpFunc, 0, sizeof(SENSOR_EXP_FUNC_S));

    pstSensorExpFunc->pfnSensorPowerUp  = CAMERA_PowerUp;
    pstSensorExpFunc->pfnSensorPowerDown = CAMERA_PowerDown;
    pstSensorExpFunc->pfnSensorDetect   = CAMERA_Detect;
    pstSensorExpFunc->pfnSensorInit     = CAMERA_Init;
    pstSensorExpFunc->pfnSensorStream   = CAMERA_Stream;
    pstSensorExpFunc->pfnSensorExit     = CAMERA_Exit;
    pstSensorExpFunc->pfnSensorSetImageMode   = CAMERA_SetImageMode;
    pstSensorExpFunc->pfnSensorEnumSnstype   = CAMERA_EnumSnstype;

    return EI_SUCCESS;
}

/****************************************************************************
 * callback structure                                                       *
 ****************************************************************************/

static EI_S32 CAMERA_CtxInit(VISS_DEV dev)
{
    SNS_STATE_S *pastSnsStateCtx = EI_NULL;

    SNS_GET_CTX(dev, pastSnsStateCtx);

    CAMERA_CHECK_POINTER(pastSnsStateCtx);

    memset(pastSnsStateCtx, 0, sizeof(SNS_STATE_S));

    pastSnsStateCtx->pstPowerUpAct      = s_stPowerUpAct;
    pastSnsStateCtx->pstPowerDownAct    = s_sPowerDownAct;
    pastSnsStateCtx->u8PwrUpActs        = ARRAY_SIZE(s_stPowerUpAct);
    pastSnsStateCtx->u8PwrDnActs        = ARRAY_SIZE(s_sPowerDownAct);

    return EI_SUCCESS;
}

static EI_VOID CAMERA_CtxExit(VISS_DEV dev)
{
    return ;
}

static EI_S32 CAMERA_RegisterVissCallback(VISS_DEV dev, SNS_TYPE_E enType)
{
    EI_S32 s32Ret;
    SENSOR_S stSns = {0};
    EI_U32 i;
    SNS_STATE_S *pstSnsState = EI_NULL;

    s32Ret = CAMERA_CtxInit(dev);
    if (EI_SUCCESS != s32Ret) {
        return EI_FAILURE;
    }

    SNS_GET_CTX(dev, pstSnsState);

    for (i = 0; i < ARRAY_SIZE(s_astSnsAttr); i++) {
        if (enType == s_astSnsAttr[i].enSnsType) {
            pstSnsState->pstSnsAttr = &s_astSnsAttr[i];
            break;
        }
    }

    pstSnsState->enSnsType = enType;
    pstSnsState->Dev = dev;

    if (i >= ARRAY_SIZE(s_astSnsAttr)) {
        PRT_VISS_ERR("%s does not support this chn configuration", SNS_NAME);
        return EI_FAILURE;
    }

    s32Ret = CAMERA_I2cInit(dev);
    if (EI_SUCCESS != s32Ret) {
        return EI_FAILURE;
    }

    stSns.stSnsAttrInfo.eSensorId = SNS_ID;
    stSns.stSnsAttrInfo.enDevType = DEV_TYPE;
    stSns.stSnsAttrInfo.pstSns = pstSnsState;

    s32Ret  = CAMERA_InitSensorExpFunction(&stSns.stSnsAttrInfo.stSnsExp);
    s32Ret |= VISS_SensorRegCallBack(dev, &stSns);
    if (EI_SUCCESS != s32Ret) {
        PRT_VISS_ERR("%s sensor register callback function failed!\n", SNS_NAME);
        return s32Ret;
    }

    s32Ret = CAMERA_OpenI2c(pstSnsState);
    CAMERA_CHECK_SUCCESS(s32Ret);

    return EI_SUCCESS;
}

static EI_S32 CAMERA_UnregisterVissCallback(VISS_DEV dev)
{
    EI_S32 s32Ret;
    SNS_STATE_S *pstSnsState = EI_NULL;

    SNS_GET_CTX(dev, pstSnsState);

    s32Ret = CAMERA_ExitI2c(pstSnsState);
    CAMERA_CHECK_SUCCESS(s32Ret);

    s32Ret = VISS_SensorUnRegCallBack(dev, SNS_ID);
    if (EI_SUCCESS != s32Ret) {
        PRT_VISS_ERR("%s sensor unregister callback function failed!\n", SNS_NAME);
        return s32Ret;
    }

    CAMERA_CtxExit(dev);

    return EI_SUCCESS;
}

static EI_S32 CAMERA_GetVissDevAttrBySns(SNS_TYPE_E enType,
    VISS_DEV_ATTR_S *pstVissDevAttr)
{
    EI_U32 i;
    const SNS_TYPE_ATTR_S *pstSnsType;

    for (i = 0; i < ARRAY_SIZE(s_astSnsAttr); i++) {
        if (enType == s_astSnsAttr[i].enSnsType) {
            pstSnsType = &s_astSnsAttr[i];
            pstVissDevAttr->stSize          = pstSnsType->stSize;
            pstVissDevAttr->enWorkMode      = pstSnsType->enWorkMode;
            pstVissDevAttr->mClock          = pstSnsType->u32Mclock;
            pstVissDevAttr->enPixelFormat   = pstSnsType->enPixelFormat;
            pstVissDevAttr->enWdrMode       = pstSnsType->enWdrMode;
            pstVissDevAttr->enIspWdrMode    = pstSnsType->enIspWdrMode;
            pstVissDevAttr->enRgbSeq        = pstSnsType->enRgbSeq;
            pstVissDevAttr->u32ModuleClk    = pstSnsType->u32ModuleClk;
            pstVissDevAttr->u32Fps          = pstSnsType->u32FrameRate;
            pstVissDevAttr->u32IspClk       = pstSnsType->u32IspClk;
            pstVissDevAttr->u32IppuClk      = pstSnsType->u32IppuClk;
            pstVissDevAttr->pcSnsName       = SNS_NAME;
            pstVissDevAttr->stDevCfg        = pstSnsType->stDevCfg;
            return EI_SUCCESS;
        }
    }

    PRT_VISS_ERR("%s does not support this dev configuration", SNS_NAME);

    return EI_FAILURE;
}

static EI_S32 CAMERA_GetVissChnAttrBySns(SNS_TYPE_E enType,
    VISS_CHN_ATTR_S *pstVissChnAttr)
{
    EI_U32 i;
    const SNS_TYPE_ATTR_S *pstSnsType;

    for (i = 0; i < ARRAY_SIZE(s_astSnsAttr); i++) {
        if (enType == s_astSnsAttr[i].enSnsType) {
            pstSnsType = &s_astSnsAttr[i];
            pstVissChnAttr->stSize           = pstSnsType->stSize;
            pstVissChnAttr->enPixelFormat    = pstSnsType->enPixelFormat;
            pstVissChnAttr->stFrameRate.s32SrcFrameRate      = pstSnsType->u32FrameRate;
            return EI_SUCCESS;
        }
    }

    PRT_VISS_ERR("%s does not support this chn configuration", SNS_NAME);

    return EI_FAILURE;

}

CAMERA_OBJ_S stCameraAr0230Obj = {
    .pfnRegisterVissCallback    = CAMERA_RegisterVissCallback,
    .pfnUnRegisterVissCallback  = CAMERA_UnregisterVissCallback,
    .pfnRegisterIspCallback     = EI_NULL,
    .pfnUnRegisterIspCallback   = EI_NULL,
    .pfnGetVissDevAttrBySns     = CAMERA_GetVissDevAttrBySns,
    .pfnGetVissChnAttrBySns     = CAMERA_GetVissChnAttrBySns,
};


#ifdef __cplusplus
#if __cplusplus
}
#endif
#endif /* __cplusplus */

